package com.demo.spring.实现mybatis与spring整合;

import java.util.Set;

import org.mybatis.spring.mapper.MapperFactoryBean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

public class MapperPostProcessor implements BeanDefinitionRegistryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		try {
			PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
			Resource[] resources = resolver.getResources("classpath:com/demo/spring/实现mybatis与spring整合/*.class");
			CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
			AnnotationBeanNameGenerator generator = new AnnotationBeanNameGenerator();
			
			MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/demo/spring/实现mybatis与spring整合/Config.class"));
			Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
			for(MethodMetadata method : methods) {
				System.out.println(method);
				Object initMethodo = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod");
				BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
				builder.setFactoryMethodOnBean(method.getMethodName(), "config");
				// 像bean3这种还需要指定装配模式，用构造方法模式
				builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
				if(initMethodo != null && initMethodo.toString().length() > 0) {
					builder.setInitMethodName(initMethodo.toString());
				}
				AbstractBeanDefinition bd = builder.getBeanDefinition();
				registry.registerBeanDefinition(method.getMethodName(), bd);
			}
			// 上面过程会把SqlSessionFactoryBean注入容器，这样下面在注册MapperFactoryBean时就可以配合AUTOWIRE_BY_TYPE注入调用到setSqlSessionFactory(...)方法进行SqlSessionFactory注入
			// AbstractAutowireCapableBeanFactory
			// if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
				// autowireByType(beanName, mbd, bw, newPvs);
			// }
			
			for (Resource resource : resources) {
				MetadataReader reader2 = factory.getMetadataReader(resource);
				ClassMetadata classMetadata = reader2.getClassMetadata();
				if(classMetadata.isInterface()) {
					AbstractBeanDefinition bd = BeanDefinitionBuilder.genericBeanDefinition(MapperFactoryBean.class)
							// spring内部会把class name转换为class对象
							.addConstructorArgValue(classMetadata.getClassName())
							.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE)
							.getBeanDefinition();
					AbstractBeanDefinition bd2 = BeanDefinitionBuilder.genericBeanDefinition(classMetadata.getClassName()).getBeanDefinition();
					String name = generator.generateBeanName(bd2, registry);
					registry.registerBeanDefinition(name, bd);
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

}
